前言
在分布式系统中,由于服务众多的关系,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件,而 Spring Cloud Config 项目就是一个能解决分布式系统需求的配置管理方案。
Spring Cloud Config 分为 server 和 client 两个部分: server 用于从 GitHub 或其他地方获取配置文件、存储,并通过 HTTP 接口的方式将它们提供给 client , client 再通过这些配置文件来初始化自身。
按照官方文档的说明,想要获取官方示例中的 https://github.com/spring-cloud-samples/config-repo/blob/master/test.json 文件,在配置好 server 之后, client 就可以访问 server 的 /{name}/{profile}/{label}/{path} (这里是 /foo/default/master/test.json ) HTTP 接口, server 会访问 GitHub 并将文件下载到本地,然后通过 HTTP 响应返回给 client 。
在这个过程中,由于 server 没有对输入的 path 进行检查的原因,所以存在一个服务端目录穿越和任意文件读取的漏洞。
环境搭建
嫌麻烦的我直接在本机上面跑了,用 maven 新建一个 spring-boot 的项目,配置文件如下:
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
</dependencies>
application.yml:
server:
port: 80
context-path: /spring-boot-quick-start
logging:
level:
root: INFO
org:
springframework:
web: DEBUG
security: DEBUG
spring:
jpa:
show-sql: true
messages:
basename: i18n/messages, i18n/messages_zh
cloud:
config:
server:
default-application-name: config-server
git:
uri: https://github.com/spring-cloud-samples/config-repo.git
label: master
management:
security:
roles: ADMIN
Application.java:
package Twings;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String args[]) {
SpringApplication.run(Application.class, args);
}
}
想要使用其他版本组件的也可以自行更改,版本可以在 maven 的仓库上查找: https://mvnrepository.com/ 。
特别方便,不过要注意下兼容的问题。
开启 Web 服务,然后访问 test.json :
漏洞复现与分析
在C盘根目录放置一个twings.txt,payload:
http://localhost/spring-boot-quick-start/foo/default/master/..%252F..%252F..%252F..%252F..%252F..%252Ftwings.txt
找到 /{name}/{profile}/{label}/{path} 路由并下断点开启调试:
因为过程很简单,调用链也不长,所以我就从简了,直接来到 findOne 函数:
这里通过相对路径的方式打开了文件,然后调用 openConnection 打开了 file 协议的 url 的连接并在 Handler类中调用 ParseUtil.decode 进行了 URL 解码得到了可以进行目录穿越的payload:
最后调用了StreamUtils.copyToString(is, Charset.forName(“UTF-8”)),将文件内容读入了字符串中进行返回:
成功穿越目录读取了文件。
参考文章:
https://cloud.spring.io/spring-cloud-static/spring-cloud.html#_serving_plain_text
https://www.cnblogs.com/shamo89/p/8016908.html
https://www.cnblogs.com/cralor/p/9239976.html
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!